<template>
    <div class="audio-recorder">
        <div class="controls">
            <div class="controls-row">
                <button @click="toggleRecording" :disabled="isProcessing && !isRecording">
                    {{ isRecording ? '停止录音' : '开始录音' }}
                </button>
                <div class="storage-toggle">
                    <label class="switch">
                        <input type="checkbox" v-model="useLocalStorage">
                        <span class="slider round"></span>
                    </label>
                    <span>{{ useLocalStorage ? '本地API' : '阿里云API' }}</span>
                </div>
                <div class="streaming-toggle">
                    <label class="switch">
                        <input type="checkbox" v-model="useStreaming" :disabled="!useLocalStorage">
                        <span class="slider round" :class="{ 'disabled': !useLocalStorage }"></span>
                    </label>
                    <span>{{ useStreaming ? '流式输出' : '完整输出' }}</span>
                    <span v-if="!useLocalStorage" class="toggle-note">(阿里云API模式下仅支持完整输出)</span>
                </div>
            </div>
        </div>
        <div v-if="isRecording" class="recording-indicator">
            正在录音... {{ recordingTime }}秒
        </div>
        <div v-if="isProcessing" class="processing-indicator">
            正在处理...
        </div>
        <div v-if="transcriptionResult" class="result">
            <h3>识别结果:</h3>
            <p>{{ transcriptionResult }}</p>
        </div>
        <div v-if="wsStatus" class="ws-status" :class="{ 'ws-connected': wsConnected }">
            WebSocket状态: {{ wsStatus }}
        </div>

        <!-- AI聊天对话框 -->
        <ChatDialog :transcriptionResult="transcriptionResult" />
    </div>
</template>

<script setup>
import { ref, onMounted, onBeforeMount, onUnmounted, watch } from 'vue';
import axios from 'axios';
import ChatDialog from './ChatDialog.vue';
// 导入Element Plus组件
import { ElMessage, ElMessageBox } from 'element-plus';
// 如果需要样式，请确保在main.js中导入了Element Plus的样式

// 组件状态
const isRecording = ref(false);
const isProcessing = ref(false);
const transcriptionResult = ref('');
const recordingTime = ref(0);
const useLocalStorage = ref(true); // 默认使用本地API
const useStreaming = ref(false); // 默认使用流式输出(WebSocket)
let recordingTimer = null;
let streamingTimer = null;
const streamingInterval = 1000; // 每1秒处理一次录音数据，从3秒改为1秒提高实时性
const minStreamingSize = 4000; // 最小流式处理数据大小（字节），从8000改为4000

// WebSocket相关
let webSocket = null;
let sessionId = null;
const wsConnected = ref(false);
const wsStatus = ref('未连接');
const lastProcessedText = ref('');

// 录音相关变量
let mediaRecorder = null;
const audioChunks = ref([]);
const streamingChunks = ref([]);
let initialConnectionAttempted = false;

// 音频处理相关变量
let audioSource = null;
let audioContext = null;
let isPlaying = ref(false);
let audioBufferQueue = [];
let pcmDataQueue = [];
let isPlayingAudio = false;
let audioProcessing = false;
let accumulatedPcmData = null; // 用于累积PCM数据
let currentSentencePcmData = null; // 当前句子的累积PCM数据
let isSentenceComplete = false; // 标记当前句子是否完成
let lastMessageTime = 0; // 上一次收到消息的时间
let sentenceTimeoutId = null; // 句子超时定时器ID
const sentenceTimeout = 800; // 句子超时时间(毫秒)，用于判断一个句子是否结束

// 音频参数
const sampleRate = 20000; // 默认采样率20kHz，适合男声和女声
const numChannels = 1;    // 默认单声道
const bytesPerSample = 2; // 默认16位音频 (2字节/样本)
const bufferSize = sampleRate / 2; // 0.5秒的缓冲区
const minBufferSize = 4000; // 最小处理块大小
const overlapSize = 100; // 重叠区域大小，用于平滑过渡

// 流式TTS相关变量
let streamingTTSActive = false;
let streamingTTSSessionId = null;
let currentTTSText = '';
let streamingAudioChunks = [];
let isBuffering = true;
let minBufferChunks = 3;
const isFirstChunk = ref(true);
let accumulatedData = new Uint8Array(0);

// 添加WAV头部处理相关变量
let hasReceivedHeader = false;
let currentRecognizedText = '';

// 添加全局WebSocket消息发送函数
window.sendWebSocketMessage = (message) => {
    if (webSocket && webSocket.readyState === WebSocket.OPEN) {
        webSocket.send(message);
        return true;
    } else {
        console.error('WebSocket未连接，无法发送消息');
        return false;
    }
};

// 监听useLocalStorage变化
watch(useLocalStorage, (newValue) => {
    if (!newValue) {
        // 如果切换到阿里云API，则强制使用完整输出
        useStreaming.value = false;
    }
});

// 在onBeforeMount中预先尝试建立连接
onBeforeMount(() => {
    console.log('组件挂载前，提前初始化WebSocket连接');
    initialConnectionAttempted = true;
    connectWebSocket();
});

// 组件挂载时设置录音设备并确保WebSocket连接
onMounted(() => {
    console.log('组件已挂载，设置音频录制器');
    setupAudioRecorder();

    // 如果预先连接失败，再次尝试连接
    if (!wsConnected.value) {
        console.log('初始连接未成功，再次尝试连接...');
        connectWebSocket();
    }

    // 定期检查WebSocket连接状态
    const connectionChecker = setInterval(() => {
        if (!wsConnected.value && !webSocket) {
            console.log('WebSocket未连接，尝试重新连接...');
            connectWebSocket();
        } else if (webSocket && webSocket.readyState !== WebSocket.OPEN) {
            console.log(`WebSocket状态异常: ${webSocket.readyState}，尝试重新连接...`);
            connectWebSocket();
        }
    }, 3000); // 每3秒检查一次

    // 在组件卸载时清除定时器
    onUnmounted(() => {
        clearInterval(connectionChecker);
    });
});

// 组件卸载时清理
onUnmounted(() => {
    console.log('组件卸载，清理资源');
    stopRecording();
    clearInterval(recordingTimer);
    clearInterval(streamingTimer);
    disconnectWebSocket();

    if (audioContext) {
        audioContext.close().catch(err => console.error('关闭AudioContext时出错:', err));
        audioContext = null;
    }

    streamingTTSActive = false;
    streamingTTSSessionId = null;
    pcmDataQueue = [];
    streamingAudioChunks = [];
    audioChunks.value = [];
    audioBufferQueue = [];
    accumulatedData = new Uint8Array(0);
    hasReceivedHeader = false;
    isProcessing.value = false;
});

// 连接WebSocket
const connectWebSocket = () => {
    try {
        // 创建WebSocket连接
        let wsUrl;

        // 使用相对路径，通过Vite代理转发
        wsUrl = `/ws/voice`;

        console.log('正在连接WebSocket...', wsUrl);

        // 关闭之前的连接
        if (webSocket && webSocket.readyState !== WebSocket.CLOSED) {
            console.log('关闭现有WebSocket连接');
            webSocket.close();
        }

        // 创建新的WebSocket连接
        webSocket = new WebSocket(wsUrl);

        // 设置连接超时
        const connectionTimeout = setTimeout(() => {
            if (webSocket && webSocket.readyState === WebSocket.CONNECTING) {
                console.log('WebSocket连接超时');
                webSocket.close();
            }
        }, 10000); // 10秒超时，适应内网穿透场景下的延迟

        // 连接建立时的处理
        webSocket.onopen = (event) => {
            clearTimeout(connectionTimeout); // 清除超时计时器
            wsConnected.value = true;
            wsStatus.value = '已连接';
            console.log('WebSocket连接成功！', event);

            // 发送连接确认消息
            const connectionMsg = {
                type: 'connection_ready',
                timestamp: Date.now()
            };
            webSocket.send(JSON.stringify(connectionMsg));
        };

        // 接收消息的处理
        webSocket.onmessage = async (event) => {
            try {
                // 已收到消息，说明连接正常
                wsConnected.value = true;
                wsStatus.value = '已连接';

                // 检查消息类型
                if (event.data instanceof Blob || event.data instanceof ArrayBuffer) {
                    // 处理二进制数据（TTS音频数据）
                    console.log('收到WebSocket二进制消息，大小:', event.data instanceof Blob ? event.data.size : event.data.byteLength);

                    // 更新最后收到消息的时间
                    lastMessageTime = Date.now();

                    // 重置句子超时定时器
                    if (sentenceTimeoutId) {
                        clearTimeout(sentenceTimeoutId);
                    }

                    // 设置新的句子超时定时器
                    sentenceTimeoutId = setTimeout(() => {
                        console.log('句子超时，判定当前句子结束');
                        completeSentence();
                    }, sentenceTimeout);

                    await handleTTSAudioData(event.data);
                    return;
                }

                console.log('收到WebSocket消息:', event.data.substring(0, 100) + (event.data.length > 100 ? '...' : ''));
                const message = JSON.parse(event.data);

                if (message.type === 'connection') {
                    sessionId = message.sessionId;
                    console.log('会话ID:', sessionId);
                } else if (message.type === 'connection_test') {
                    // 处理连接测试消息
                    console.log('收到连接测试消息:', message);
                    // 发送确认消息
                    const confirmMsg = {
                        type: 'connection_test_ack',
                        session_id: message.session_id,
                        timestamp: Date.now()
                    };
                    webSocket.send(JSON.stringify(confirmMsg));
                } else if (message.type === 'tts_progress') {
                    // 处理TTS进度消息
                    console.log('收到TTS进度消息:', message);
                } else if (message.type === 'recognition') {
                    // 处理识别结果
                    if (message.text !== undefined) {
                        // 更新完整文本
                        transcriptionResult.value = message.text;

                        // 检查是否有增量文本
                        if (message.new_text && useStreaming.value) {
                            console.log('收到增量文本:', message.new_text);
                        }

                        // 保存当前文本用于与TTS数据关联
                        currentRecognizedText = message.text;

                        // 将识别结果添加到AI聊天框中，但仅在最终结果时
                        if (message.isFinal) {
                            // 使用组件内状态变量进行去重，比localStorage更可靠
                            if (message.text !== lastProcessedText.value) {
                                console.log('发送新识别文本:', message.text);
                                lastProcessedText.value = message.text;

                                const ttsEvent = new CustomEvent('recognition-result', {
                                    detail: {
                                        text: message.text,
                                        timestamp: Date.now() // 添加时间戳以帮助接收方检测重复
                                    }
                                });
                                window.dispatchEvent(ttsEvent);
                            } else {
                                console.log('跳过重复文本:', message.text);
                            }

                            // 如果是最终结果，确保重置处理状态
                            setTimeout(() => {
                                isProcessing.value = false;
                            }, 500);
                        }
                    }
                } else if (message.type === 'tts_metadata') {
                    // 处理TTS元数据
                    console.log('收到TTS元数据:', message);

                    // 检查是否为流式TTS
                    if (message.streaming === true) {
                        console.log('检测到流式TTS模式');
                        streamingTTSActive = true;
                        streamingTTSSessionId = message.session_id || sessionId;

                        // 重置音频缓冲区
                        streamingAudioChunks = [];
                        wavHeaderData = null;
                        isBuffering = true;

                        // 准备接收流式音频数据
                        console.log('准备接收流式TTS音频数据，会话ID:', streamingTTSSessionId);
                    }

                    // 保存元数据中的文本，以便后续与音频数据关联
                    currentTTSText = message.text;
                } else if (message.type === 'tts_complete') {
                    // 处理TTS完成消息
                    console.log('收到TTS完成消息:', message);
                    streamingTTSActive = false;
                    streamingTTSSessionId = null;

                    // 确保完成当前句子
                    completeSentence();

                    // 处理TTS完成
                    handleTTSComplete();
                } else if (message.type === 'ai_response' || message.type === 'ai_processing' || message.type === 'ai_status') {
                    // 处理AI响应消息
                    if (message.type === 'ai_response') {
                        // 实时更新UI显示流式AI响应文本
                        if (message.text) {
                            const textLength = (message.text || '').length;
                            console.log(`收到AI流式响应文本块: 长度=${textLength}, 文本="${message.text}", 是否完成=${message.done || false}`);

                            // 收到任何响应文本后，就允许用户开始新的录音（不必等待响应完成）
                            if (!isRecording.value) {
                                isProcessing.value = false;
                            }

                            // 记录更多有用的调试信息
                            if (message.full_text) {
                                console.log(`AI响应完整文本长度: ${message.full_text.length}`);
                            }

                            // 仅在最终响应时记录状态变化
                            if (message.done) {
                                console.log('收到AI响应完成标志');
                            }
                        } else {
                            console.warn('收到的AI响应没有文本内容');
                        }
                    } else if (message.type === 'ai_status') {
                        // 处理AI状态更新
                        console.log('收到AI状态更新:', JSON.stringify(message));

                        // 在收到状态消息时重置处理状态，允许用户录音
                        if (message.status === 'completed' && !isRecording.value) {
                            isProcessing.value = false;
                            console.log('AI处理已完成，重置处理状态');
                        }
                    } else if (message.type === 'ai_processing') {
                        // 处理AI处理状态
                        console.log('收到AI处理状态:', JSON.stringify(message));

                        // 如果处理状态为完成，重置处理状态
                        if (message.status === 'completed' && !isRecording.value) {
                            isProcessing.value = false;
                            console.log('AI处理已完成，重置处理状态');
                        }
                    }

                    // 将AI相关消息分发给ChatDialog组件处理
                    if (typeof window.handleWebSocketAIMessage === 'function') {
                        try {
                            window.handleWebSocketAIMessage(message);
                        } catch (e) {
                            console.error('调用handleWebSocketAIMessage时出错:', e);
                        }
                    } else {
                        console.warn('未找到AI消息处理函数');
                    }
                } else if (message.type === 'error') {
                    console.error('WebSocket错误:', message.message);
                    if (!isRecording.value) {
                        transcriptionResult.value = '错误: ' + message.message;
                    }
                    // 发生错误时也重置处理状态
                    isProcessing.value = false;
                    streamingTTSActive = false;
                    audioQueue = [];
                }
            } catch (e) {
                console.error('解析WebSocket消息失败:', e);
                // 解析失败时也重置处理状态
                isProcessing.value = false;
            }
        };

        // 错误处理
        webSocket.onerror = (event) => {
            clearTimeout(connectionTimeout); // 清除超时计时器
            console.error('WebSocket连接错误');
            wsConnected.value = false;
            wsStatus.value = '连接错误';
        };

        // 连接关闭的处理
        webSocket.onclose = (event) => {
            clearTimeout(connectionTimeout); // 清除超时计时器
            wsConnected.value = false;
            wsStatus.value = '已断开';

            console.log('WebSocket连接已关闭:', event.code, event.reason);

            // 如果在录音状态下连接中断，尝试重连
            if (isRecording.value) {
                console.log('录音进行中，立即尝试重新连接WebSocket');
                setTimeout(connectWebSocket, 300); // 300ms后重连
            }
        };
    } catch (e) {
        console.error('建立WebSocket连接时出错:', e);
        wsStatus.value = '连接错误: ' + e.message;
    }
};

// 设置音频录制器
const setupAudioRecorder = async () => {
    try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

        // 尝试使用更好的音频格式
        const options = {};
        if (MediaRecorder.isTypeSupported('audio/wav')) {
            options.mimeType = 'audio/wav';
        } else if (MediaRecorder.isTypeSupported('audio/webm')) {
            options.mimeType = 'audio/webm';
        }

        mediaRecorder = new MediaRecorder(stream, options);

        // 当有录音数据可用时
        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                audioChunks.value.push(event.data);
                // 如果是流式处理模式，也添加到流式处理数组
                if (useStreaming.value) {
                    streamingChunks.value.push(event.data);
                }
            }
        };

        // 录音停止时处理数据
        mediaRecorder.onstop = () => {
            if (!useStreaming.value) {
                processRecording();
            }
        };

        console.log('音频录制器已设置，使用MIME类型:', mediaRecorder.mimeType);
    } catch (error) {
        console.error('设置音频录制器时出错:', error);
        alert('无法访问麦克风，请确保已授予权限。');
    }
};

// 切换录音状态
const toggleRecording = () => {
    if (isRecording.value) {
        stopRecording();
    } else {
        startRecording();
    }
};

// 开始录音
const startRecording = async () => {
    try {
        transcriptionResult.value = '';
        audioChunks.value = [];
        streamingChunks.value = [];
        isRecording.value = true;
        recordingTime.value = 0;

        // 如果WebSocket未连接，尝试重新连接
        if ((!wsConnected.value || !webSocket || webSocket.readyState !== WebSocket.OPEN) && useStreaming.value) {
            connectWebSocket();
            // 等待连接建立
            await new Promise(resolve => setTimeout(resolve, 1000));
        }

        // 首先尝试获取用户的媒体流
        const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });

        // 尝试使用更好的音频格式
        const options = {};
        if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) {
            options.mimeType = 'audio/webm;codecs=opus';
        } else if (MediaRecorder.isTypeSupported('audio/webm')) {
            options.mimeType = 'audio/webm';
        }

        mediaRecorder = new MediaRecorder(mediaStream, options);
        console.log('创建MediaRecorder使用MIME类型:', mediaRecorder.mimeType);

        // 媒体数据可用时收集数据
        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                audioChunks.value.push(event.data);
                // 如果是流式处理模式，也添加到流式处理数组
                if (useStreaming.value) {
                    streamingChunks.value.push(event.data);
                }
            }
        };

        // 开始录音，设置较小的时间片以获取更多数据块
        mediaRecorder.start(250); // 每250ms触发一次ondataavailable事件

        console.log('开始录音...');

        // 如果开启了流式输出，设置定时器定期处理数据
        if (useStreaming.value) {
            streamingTimer = setInterval(() => {
                processNativeWebSocketStreaming(false);
            }, streamingInterval);
        }

        // 开始计时
        recordingTimer = setInterval(() => {
            recordingTime.value++;
        }, 1000);
    } catch (error) {
        console.error('录音失败:', error);
        transcriptionResult.value = '无法访问麦克风: ' + error.message;
        isRecording.value = false;
    }
};

// 停止录音
const stopRecording = async () => {
    if (!isRecording.value) return;

    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop();
        console.log('停止录音');
    }

    isRecording.value = false;
    clearInterval(recordingTimer);

    // 如果是流式处理，清除流式处理定时器
    if (useStreaming.value) {
        clearInterval(streamingTimer);
        // 处理最后一批数据
        if (audioChunks.value.length > 0) {
            console.log('处理最终音频数据，共 ' + audioChunks.value.length + ' 个片段');
            processNativeWebSocketStreaming(true);
        } else {
            // 确保如果没有数据也可以重置处理状态
            isProcessing.value = false;
        }
        return;
    }

    // 非流式模式下，等待所有音频数据收集完毕后再处理
    setTimeout(() => {
        processRecording();
    }, 500);
};

// 使用原生WebSocket处理流式音频数据
const processNativeWebSocketStreaming = async (isFinal = false) => {
    if ((!isRecording.value && !isFinal) || !wsConnected.value || !webSocket || webSocket.readyState !== WebSocket.OPEN) return;

    // 确保有音频数据
    if (streamingChunks.value.length === 0) {
        console.log('没有音频数据可处理');
        // 如果没有数据并且是最终调用，重置处理状态
        if (isFinal) {
            isProcessing.value = false;
        }
        return;
    }

    // 创建当前批次的音频blob
    const audioBlob = new Blob(streamingChunks.value);
    console.log(`通过WebSocket处理${isFinal ? '最终' : '流式'}音频数据，当前批次大小: ${audioBlob.size} 字节`);

    // 如果blob太小且不是最终数据，则跳过处理
    if (audioBlob.size < minStreamingSize && !isFinal) {
        console.log(`音频数据太小 (${audioBlob.size} bytes)，跳过处理`);
        return;
    }

    // 只在非final状态下设置处理中，这样可以保证最终状态下重置按钮状态
    if (!isFinal) {
        isProcessing.value = true;
    }

    try {
        // 先发送元数据消息
        const metadataMessage = {
            type: 'audio_binary',
            format: mediaRecorder.mimeType || 'audio/webm',
            useLocalStorage: useLocalStorage.value,
            isFinal: isFinal,
            size: audioBlob.size,
            streaming: useStreaming.value  // 明确指明是否为流式处理
        };

        // 发送元数据JSON
        webSocket.send(JSON.stringify(metadataMessage));
        console.log('已发送音频元数据:', metadataMessage);

        // 将Blob转换为ArrayBuffer，准备发送二进制数据
        const arrayBuffer = await audioBlob.arrayBuffer();

        // 直接发送二进制数据
        webSocket.send(arrayBuffer);
        console.log(`已发送二进制音频数据，大小: ${arrayBuffer.byteLength} 字节`);

        // 清空当前批次的音频数据，但保留全部数据用于最终处理
        if (!isFinal) {
            streamingChunks.value = [];
        }

        // 如果是最终数据，在发送后重置处理状态
        if (isFinal) {
            // 延迟重置，给服务器一些处理时间
            setTimeout(() => {
                isProcessing.value = false;
            }, 1000);
        }
    } catch (err) {
        console.error('WebSocket处理音频失败:', err);
        isProcessing.value = false;
    }
};

// 处理完整录音（非WebSocket方式）
const processRecording = async () => {
    isProcessing.value = true;
    console.log('开始处理完整录音...');

    // 创建完整的音频blob（不指定类型，保留原始格式）
    const audioBlob = new Blob(audioChunks.value);
    console.log('音频数据大小:', audioBlob.size, '字节', '类型:', audioBlob.type || mediaRecorder.mimeType || '未知');

    try {
        // 确保WebSocket连接
        if (!wsConnected.value || !webSocket || webSocket.readyState !== WebSocket.OPEN) {
            console.log('WebSocket未连接，尝试重新连接...');
            await connectWebSocket();
            // 等待连接建立
            await new Promise(resolve => setTimeout(resolve, 1000));
        }

        // 先发送元数据消息
        const metadataMessage = {
            type: 'audio_binary',
            format: mediaRecorder.mimeType || 'audio/webm',
            useLocalStorage: useLocalStorage.value,
            isFinal: true,
            size: audioBlob.size,
            streaming: false  // 明确指明非流式处理
        };

        // 发送元数据JSON
        webSocket.send(JSON.stringify(metadataMessage));
        console.log('已发送音频元数据:', metadataMessage);

        // 将Blob转换为ArrayBuffer，准备发送二进制数据
        const arrayBuffer = await audioBlob.arrayBuffer();

        // 直接发送二进制数据
        webSocket.send(arrayBuffer);
        console.log(`已发送二进制音频数据，大小: ${arrayBuffer.byteLength} 字节`);
    } catch (error) {
        console.error('处理录音失败:', error);
        transcriptionResult.value = '处理录音失败: ' + error.message;
        isProcessing.value = false;
    }
};

// 完成当前句子的处理
const completeSentence = () => {
    if (currentSentencePcmData && currentSentencePcmData.length > 0) {
        console.log(`完成句子处理，总长度: ${currentSentencePcmData.length}样本`);

        // 将完整句子添加到播放队列
        pcmDataQueue.push(currentSentencePcmData);

        // 重置当前句子数据
        currentSentencePcmData = null;

        // 如果当前没有在处理数据，开始处理
        if (!audioProcessing) {
            processAudioQueue();
        }
    }

    // 重置超时定时器
    if (sentenceTimeoutId) {
        clearTimeout(sentenceTimeoutId);
        sentenceTimeoutId = null;
    }
};

// 处理TTS音频数据
const handleTTSAudioData = async (data) => {
    try {
        // 检查输入数据是否为空
        if (!data || (data instanceof Blob && data.size === 0) ||
            (data instanceof ArrayBuffer && data.byteLength === 0)) {
            console.warn('收到空的TTS音频数据');
            return;
        }

        // 如果数据是Blob类型，转换为ArrayBuffer
        let arrayBuffer;
        if (data instanceof Blob) {
            arrayBuffer = await data.arrayBuffer();
        } else {
            arrayBuffer = data;
        }

        // 创建一个Uint8Array视图用于处理数据
        const newData = new Uint8Array(arrayBuffer);
        console.log(`收到PCM音频数据: ${newData.length}字节`);

        // 确保数据对齐（16位PCM需要2字节对齐）
        const dataLength = newData.length;
        const alignedLength = dataLength - (dataLength % 2);
        const alignedData = alignedLength < dataLength ? newData.slice(0, alignedLength) : newData;

        // 合并新的音频数据到累积缓冲区
        const combinedData = new Uint8Array(accumulatedData.length + alignedData.length);
        combinedData.set(accumulatedData, 0);
        combinedData.set(alignedData, accumulatedData.length);
        accumulatedData = combinedData;

        // 当累积的数据超过一定大小时处理它
        if (accumulatedData.length >= minBufferSize) {
            console.log(`处理音频块: ${accumulatedData.length}字节`);

            // 将PCM数据转换为Int16Array
            const pcmData = new Int16Array(accumulatedData.buffer, accumulatedData.byteOffset, accumulatedData.byteLength / 2);

            // 将数据添加到当前句子中
            addToPcmSentence(pcmData);

            // 清空累积的数据
            accumulatedData = new Uint8Array(0);
        }
    } catch (error) {
        console.error('处理TTS音频数据时出错:', error);
    }
};

// 将PCM数据添加到当前句子
const addToPcmSentence = (pcmData) => {
    try {
        // 如果当前没有句子数据，创建一个新的
        if (!currentSentencePcmData) {
            currentSentencePcmData = pcmData;
        } else {
            // 否则，将新数据附加到当前句子
            const newData = new Int16Array(currentSentencePcmData.length + pcmData.length);
            newData.set(currentSentencePcmData, 0);
            newData.set(pcmData, currentSentencePcmData.length);
            currentSentencePcmData = newData;
        }

        console.log(`当前句子PCM数据已累积至 ${currentSentencePcmData.length} 样本`);
    } catch (error) {
        console.error('添加PCM数据到句子时出错:', error);
        // 出错时重置句子数据
        currentSentencePcmData = null;
    }
};

// 处理音频队列
const processAudioQueue = async () => {
    if (pcmDataQueue.length === 0) {
        audioProcessing = false;
        return;
    }

    audioProcessing = true;

        // 确保AudioContext已初始化
    if (!audioContext) {
        try {
            window.AudioContext = window.AudioContext || window.webkitAudioContext;
            audioContext = new AudioContext({ sampleRate: sampleRate });
            console.log('AudioContext已初始化，采样率:', audioContext.sampleRate);
        } catch (error) {
            console.error('初始化AudioContext失败:', error);
            audioProcessing = false;
            return;
        }
    }

    // 从队列中获取PCM数据
    const pcmData = pcmDataQueue.shift();

    // 将Int16Array转换为Float32Array，应用平滑处理
    const float32Data = new Float32Array(pcmData.length);
    for (let i = 0; i < pcmData.length; i++) {
        // 将16位整数(-32768 to 32767)转换为浮点数(-1.0 to 1.0)
        float32Data[i] = pcmData[i] / 32768.0;

        // 对首尾进行平滑处理，减少爆音
        const fadeLength = Math.min(500, Math.floor(pcmData.length * 0.005));
        if (i < fadeLength) {
            // 淡入
            float32Data[i] *= (i / fadeLength);
        } else if (i > pcmData.length - fadeLength) {
            // 淡出
            float32Data[i] *= ((pcmData.length - i) / fadeLength);
        }
    }

    try {
        // 创建音频缓冲区
        const audioBuffer = audioContext.createBuffer(numChannels, float32Data.length, sampleRate);

        // 将数据复制到缓冲区
        audioBuffer.copyToChannel(float32Data, 0);

        // 创建音频源
        const source = audioContext.createBufferSource();
        source.buffer = audioBuffer;

        // 创建音频处理节点
        const gainNode = audioContext.createGain();
        gainNode.gain.value = 1.0; // 可以调整音量

        // 连接节点
        source.connect(gainNode);
        gainNode.connect(audioContext.destination);

        // 播放结束后处理下一个
        source.onended = () => {
            console.log('句子音频播放完成，长度:', float32Data.length);
            // 立即处理下一个
            processAudioQueue();
        };

        // 开始播放
        source.start();
        console.log(`开始播放完整句子: ${float32Data.length}样本`);

    } catch (error) {
        console.error('创建或播放音频时出错:', error);
        // 出错时继续处理队列
        processAudioQueue();
    }
};

// 处理TTS完成事件
const handleTTSComplete = () => {
    try {
        console.log('TTS流处理完成');

        // 处理剩余的音频数据（如果有）
        if (accumulatedData.length > 0) {
            console.log(`处理剩余数据: ${accumulatedData.length}字节`);

            // 确保数据对齐
            const dataLength = accumulatedData.length;
            const alignedLength = dataLength - (dataLength % 2);

            if (alignedLength > 0) {
                // 将PCM数据转换为Int16Array
                const pcmData = new Int16Array(accumulatedData.buffer, accumulatedData.byteOffset, alignedLength / 2);

                // 将数据添加到当前句子
                addToPcmSentence(pcmData);

                // 确保完成当前句子
                completeSentence();
            }
        } else if (currentSentencePcmData) {
            // 如果有当前句子，完成它
            completeSentence();
        }

        // 重置状态变量
        accumulatedData = new Uint8Array(0);
        isFirstChunk.value = true;

        // 清除所有超时定时器
        if (sentenceTimeoutId) {
            clearTimeout(sentenceTimeoutId);
            sentenceTimeoutId = null;
        }

        console.log('TTS处理完成，队列长度:', pcmDataQueue.length);
    } catch (error) {
        console.error('处理TTS完成事件时出错:', error);
    }
};

// 断开WebSocket连接
const disconnectWebSocket = () => {
    if (webSocket && webSocket.readyState === WebSocket.OPEN) {
        webSocket.close();
        wsConnected.value = false;
        wsStatus.value = '已断开';
        console.log('已断开WebSocket连接');
    }
};
</script>

<style scoped>
.audio-recorder {
    padding: 20px;
    border-radius: 8px;
    background-color: #f9f9f9;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    max-width: 500px;
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}

.controls {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin-bottom: 15px;
    gap: 10px;
    width: 100%;
}

.controls-row {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    gap: 10px;
    margin-bottom: 5px;
}

button {
    padding: 10px 20px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s;
    flex: 1;
    min-width: 120px;
    max-width: 200px;
    text-align: center;
}

button:hover {
    background-color: #45a049;
}

button:disabled {
    background-color: #cccccc;
    cursor: not-allowed;
}

.recording-indicator {
    color: #ff0000;
    font-weight: bold;
    margin: 10px 0;
    animation: blink 1s infinite;
    text-align: center;
}

.processing-indicator {
    color: #0066cc;
    font-weight: bold;
    margin: 10px 0;
    text-align: center;
}

.result {
    margin-top: 20px;
    padding: 15px;
    background-color: #e9f7ef;
    border-radius: 4px;
    border-left: 4px solid #4CAF50;
    text-align: left;
}

.result h3 {
    margin-top: 0;
    color: #2e7d32;
    text-align: center;
}

.ws-status {
    margin-top: 10px;
    font-size: 12px;
    color: #777;
    text-align: center;
}

.ws-connected {
    color: #4CAF50;
}

@keyframes blink {
    50% {
        opacity: 0.5;
    }
}

/* 开关样式 */
.storage-toggle,
.streaming-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    flex: 1;
    min-width: 150px;
}

.switch {
    position: relative;
    display: inline-block;
    width: 60px;
    height: 34px;
}

.switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ccc;
    transition: .4s;
}

.slider:before {
    position: absolute;
    content: "";
    height: 26px;
    width: 26px;
    left: 4px;
    bottom: 4px;
    background-color: white;
    transition: .4s;
}

input:checked+.slider {
    background-color: #2196F3;
}

input:focus+.slider {
    box-shadow: 0 0 1px #2196F3;
}

input:checked+.slider:before {
    transform: translateX(26px);
}

.slider.round {
    border-radius: 34px;
}

.slider.round:before {
    border-radius: 50%;
}

.slider.disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.toggle-note {
    font-size: 12px;
    color: #f57c00;
    margin-left: 5px;
    font-style: italic;
}
</style>